﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Vortex.Drawing;
using Vortex.Utils;
using Vortex.Input;

namespace Vortex.Tutorials.WindowsFormsIntegration {
    public partial class WindowsFormsIntegrationForm : Form {
        static Point DYNAMIC_BITMAP_OFFSET = new Point(450, 300);
        static readonly Size DYNAMIC_BITMAP_SIZE = new Size(512, 256);

        KeyboardListener _Keyboard;
        MouseListener _Mouse;

        ///<summary>Drawing Control Objects References</summary>
        SingleContextDevice _Device;
        Canvas2D _Canvas;
        Texture _Background;
        Texture _BitmapReflection;

        Bitmap _DynamicBitmap;

        public WindowsFormsIntegrationForm() {
            InitializeComponent();
        }

        private void WindowsFormsIntegrationForm_Load(object sender, EventArgs e) {
            _Keyboard = new KeyboardListener();
            _Mouse = new MouseListener(TargetDrawingPanel.Handle);

			//close form on escape
            _Keyboard.KeyUp += delegate(VirtualKey key) {
                if (key == VirtualKey.Escape) {
                    Close();
                }
            };

			//move box on left button drag
            _Mouse.Move += delegate(MouseMoveActionInfo info) {
                if (info.IsLeftButtonDown) {
					DYNAMIC_BITMAP_OFFSET.X += info.LocationDelta.X;
                    DYNAMIC_BITMAP_OFFSET.Y += info.LocationDelta.Y;
                }
            };

            Application.AddMessageFilter(_Mouse);
            Application.AddMessageFilter(_Keyboard);
            

            //create drawing device and target it to some window (in this sample - Panel Surface)
            _Device = new SingleContextDevice(TargetDrawingPanel.Handle);
            //create canvas for newly created device
            _Canvas = _Device.Context.Canvas;

            //load texture background through bitmap proxy, it just works
            using (Bitmap bitmap = new Bitmap("data/graphics/tornado.jpg")) {
                _Background = new Texture(bitmap);
            }

            //create bitmap on which we will draw with System.Drawing methods
            _DynamicBitmap = new Bitmap(DYNAMIC_BITMAP_SIZE.Width, DYNAMIC_BITMAP_SIZE.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            //create texture which will reflect dynamic bitmap content
            _BitmapReflection = new Texture(DYNAMIC_BITMAP_SIZE.Width, DYNAMIC_BITMAP_SIZE.Height, PixelFormat.A8R8G8B8);

            //copy content of dynamic bitmap into bitmap reflection texture
            CopyDynamicBitmapToTexture();

            //add event handler to dispose everything at the end
            Disposed += new EventHandler(WindowsFormsIntegrationForm_Disposed);
        }

        private void WindowsFormsIntegrationForm_Disposed(object sender, EventArgs e) {
            Application.RemoveMessageFilter(_Mouse);
            Application.RemoveMessageFilter(_Keyboard);
            _Keyboard.Dispose();

            //free used resource at the end
            _BitmapReflection.Dispose();
            _Background.Dispose();
            _Canvas.Dispose();
            _Device.Dispose();
        }

        private void UpdateTarget() {
            //start new domain (device automatically begins new frame)
            if (_Device.BeginScene()) {
                //now we can draw frame content
                DrawFrameContent();
                //finalize canvas drawing
                _Device.EndScene();
                //present frame from back-buffer to target window (Panel)
                _Device.Context.Present();
            } else {
                //reset device (try until it will be successfully reset)
                _Device.TryReset();
            }
        }

        private void DrawFrameContent() {
            //clear background
            _Canvas.DrawSprite(_Canvas.Region, _Background.ToSprite(), ColorU.White);

            //draw reflection bitmap
            Rect rect = Rect.FromPoint(DYNAMIC_BITMAP_OFFSET.X, DYNAMIC_BITMAP_OFFSET.Y, DYNAMIC_BITMAP_SIZE.Width, DYNAMIC_BITMAP_SIZE.Height);
            _Canvas.DrawSprite(rect, _BitmapReflection.ToSprite(), ColorU.White);
            _Canvas.DrawRect(rect.Inflate(new Vector2(1, 1)), ColorU.LightBlue);

            //draw text information
            _Canvas.DrawTextLayout(SpriteFont.Console, _Canvas.Region.Deflate(new Vector2(12, 12)), ComposeInfoString(), TextLayout.Default, ColorU.White);

            //draw red background
            _Canvas.DrawRect(_Canvas.Region.Deflate(new Vector2(5, 5)), ColorU.White);
            _Canvas.DrawRect(_Canvas.Region.Deflate(new Vector2(7, 7)), ColorU.White);

            if (_Mouse.IsOverWindow) {
				Rect ellipseRect = Rect.FromBox(100, 150, 300, 200);
				_Canvas.DrawFilledEllipse(ellipseRect, ColorU.Red.MultiplyAlpha(0.5f));
				_Canvas.DrawEllipse(ellipseRect, new LineStyle(2.0f, LineStroke.Dotted), ColorU.Red);
				_Canvas.DrawTextLayout(SpriteFont.Default, ellipseRect.Deflate(30, 20), "Ellipse id displayed if cursor in window!", TextLayout.Center | TextLayout.Middle, ColorU.White);
            }
        }

        private string ComposeInfoString() {
            return string.Format("Adapter: {0}\nDriver: {1}\n\nMax Texture Size: {2}x{3}\nMax Texture Repeat: {4}\nMax Texture Aspect Ratio: 1/{5}\n\nAvailable Texture Memory: {6} MB", _Device.Info.AdapterName, _Device.Info.DriverName, _Device.Info.MaxTextureWidth, _Device.Info.MaxTextureHeight, _Device.Info.MaxTextureRepeat, _Device.Info.MaxTextureAspectRatio, _Device.AvailableTextureMemory);
        }

        private void TargetDrawingPanel_Paint(object sender, PaintEventArgs e) {
            //in paint event for target we need just present currently available frame
            _Device.Context.Present();
        }

        private void TargetDrawingPanel_Resize(object sender, EventArgs e) {
            //we need manually setup new device buffer parameters
            _Device.Context.Resize();           

            //after device buffer is resized
            UpdateTarget();
        }

        private void CopyDynamicBitmapToTexture() {
            _BitmapReflection.Surface.SetBitmapData(_DynamicBitmap);
        }

        private void RateTimer_Tick(object sender, EventArgs e) {
            //update keyboard as well
            _Keyboard.Update();
            //_Mouse.Update();

            using (Graphics graphics = Graphics.FromImage(_DynamicBitmap)) {
                Rectangle rect = new Rectangle(RandomUtils.NextInt(DYNAMIC_BITMAP_SIZE.Width), RandomUtils.NextInt(DYNAMIC_BITMAP_SIZE.Height), RandomUtils.NextInt(50), RandomUtils.NextInt(50));
                Color color = Color.FromArgb(128, RandomUtils.NextInt(255), RandomUtils.NextInt(255), RandomUtils.NextInt(255));
                Brush brush = new SolidBrush(color);

                switch(RandomUtils.NextInt(2)) {
                    case 0:
                        graphics.FillEllipse(brush, rect);
                        break;
                    default:
                        graphics.FillRectangle(brush, rect);
                        break;
                }

            }
            //update texture from bitmap cache
            CopyDynamicBitmapToTexture();

            //redraw frame
            UpdateTarget();
        }
    }
}
